<template>
  <el-card>
    <el-form ref="form" class="form" :inline="true" label-width="80px">
      <el-form-item label="用户名">
        <el-input v-model="searchValue" placeholder="请输入搜索的用户名"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" :disabled="!searchValue" @click="searchUser"
          >搜索</el-button
        >
        <el-button type="default" @click="resetData">重置</el-button>
      </el-form-item>
    </el-form>
  </el-card>
  <el-card style="margin: 10px 0px">
    <el-button type="primary" @click="addUser">添加</el-button>
    <el-button type="danger" :disabled="!selectUserId.length" @click="deleteMutiUser"
      >批量删除</el-button
    >
    <el-table ref="tableRef" :data="userList" style="margin: 10px 0px" border>
      <el-table-column type="selection"> </el-table-column>
      <el-table-column type="index" label="#" align="center"> </el-table-column>
      <el-table-column prop="id" label="ID" align="center"> </el-table-column>
      <el-table-column prop="username" label="用户名字" align="center"> </el-table-column>
      <el-table-column prop="name" label="用户名称" align="center"> </el-table-column>
      <el-table-column
        prop="roleName"
        label="用户角色"
        align="center"
        show-overflow-tooltip
      >
      </el-table-column>
      <el-table-column
        prop="createTime"
        label="创建时间"
        align="center"
        show-overflow-tooltip
      >
      </el-table-column>
      <el-table-column
        prop="updateTime"
        label="更新时间"
        align="center"
        show-overflow-tooltip
      >
      </el-table-column>
      <el-table-column label="操作" width="270px" align="center">
        <template #="{ row }">
          <el-button type="success" size="small" icon="User" @click="assignRole(row)"
            >分配角色</el-button
          >
          <el-button type="primary" size="small" icon="Edit" @click="updateUser(row)"
            >编辑</el-button
          >
          <el-popconfirm
            :title="`确定删除用户【${row.username}】吗`"
            width="260px"
            @confirm="deleteUser(row)"
          >
            <template #reference>
              <el-button type="danger" size="small" icon="Delete">删除</el-button>
            </template>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页器 -->
    <el-pagination
      v-model:current-page="currentPage"
      v-model:page-size="pageSize"
      background
      :page-sizes="[5, 10, 20]"
      layout="->, prev, pager, next, sizes, jumper, total"
      :total="total"
      @current-change="curPageChange"
      @size-change="pageSizeChange"
    >
    </el-pagination>
    <!-- 添加和修改抽屉 -->
    <el-drawer v-model="addOrEditDrawerShow">
      <template #header>
        <h4>{{ userFormData.id ? "修改用户" : "添加用户" }}</h4>
      </template>
      <template #default>
        <el-form ref="formRef" :model="userFormData" :rules="rules" label-width="120px">
          <el-form-item prop="username" label="用户姓名">
            <el-input v-model="userFormData.username" placeholder="请输入名字"></el-input>
          </el-form-item>
          <el-form-item prop="name" label="用户昵称">
            <el-input v-model="userFormData.name" placeholder="请输入昵称"></el-input>
          </el-form-item>
          <el-form-item v-if="!userFormData.id" prop="password" label="用户密码">
            <el-input v-model="userFormData.password" placeholder="请输入密码"></el-input>
          </el-form-item>
        </el-form>
      </template>
      <template #footer>
        <div style="flex: auto">
          <el-button type="primary" @click="saveUserInfo">确定</el-button>
          <el-button type="default" @click="addOrEditDrawerShow = false">取消</el-button>
        </div>
      </template>
    </el-drawer>
    <!-- 分配角色抽屉 -->
    <el-drawer v-model="assignRoleDrawerShow">
      <template #header>
        <h4>分配角色</h4>
      </template>
      <template #default>
        <el-form ref="form" label-width="80px">
          <el-form-item label="用户姓名">
            <el-input v-model="userFormData.username" :disabled="true"></el-input>
          </el-form-item>
          <el-form-item label="角色列表">
            <el-checkbox
              v-model="checkAll"
              :indeterminate="isIndeterminate"
              @change="handleCheckAllChange"
              >全选</el-checkbox
            >
            <el-checkbox-group v-model="hasRoles" @change="handleRoleCheckChange">
              <el-checkbox
                v-for="item in allRoles"
                :key="item.id"
                :value="item"
                :label="item.roleName"
              ></el-checkbox>
            </el-checkbox-group>
          </el-form-item>
        </el-form>
      </template>
      <template #footer>
        <el-button type="primary" @click="saveRoleInfo">保存</el-button>
        <el-button type="default" @click="assignRoleDrawerShow = false">取消</el-button>
      </template>
    </el-drawer>
  </el-card>
</template>

<script setup lang="ts">
import { ref, onMounted, computed, nextTick } from "vue";
import {
  reqUserList,
  reqAddUser,
  reqEditUser,
  reqAllOrHasRoles,
  reqAssignRole,
  reqDeleteUser,
  reqBatchDeleteUser,
} from "@/api/acl/user";
import {
  UserResData,
  UserObj,
  RoleObj,
  RoleResData,
  AssignRoleObj,
} from "@/api/acl/user/types";
import { ElMessage } from "element-plus";
import { useUserStore } from "@/store/modules/user";
// 用户仓库对象
const userStore = useUserStore();
// 表格实例对象
const tableRef = ref();
// 当前页
const currentPage = ref(1);
// 页面显示页面条数
const pageSize = ref(5);
// 数据总数
const total = ref(0);
// 用户账号信息列表
const userList = ref<UserObj[]>([]);
// 控制添加和修改页面的显示和隐藏
const addOrEditDrawerShow = ref(false);
// 控制分配角色页面的显示和隐藏
const assignRoleDrawerShow = ref(false);
// 保存修改之前的用户名
const oldUserName = ref("");
// 收集添加和修改用户表单数据
const userFormData = ref<UserObj>({
  username: "",
  password: "",
  name: "",
});
// 添加和修改表单实例对象
const formRef = ref();
// 用户姓名自定义校验规则
const userNameRules = (rule: any, value: any, callback: any) => {
  if (value.trim().length >= 5) {
    // 正则表达式验证是否是数组和字母的组合
    if (/^[a-zA-Z0-9]+$/.test(value)) {
      callback();
    } else {
      callback(new Error("姓名只能是数组和字母组合"));
    }
  } else {
    callback(new Error("姓名至少五位"));
  }
};
// 用户昵称自定义校验规则
const nameRules = (rule: any, value: any, callback: any) => {
  if (value.trim().length >= 5) {
    // 正则表达式验证是否是数组和字母的组合
    if (/^[a-zA-Z0-9]+$/.test(value)) {
      callback();
    } else {
      callback(new Error("昵称只能是数组和字母组合"));
    }
  } else {
    callback(new Error("昵称至少五位"));
  }
};
// 用户密码自定义校验规则
const pwdRules = (rule: any, value: any, callback: any) => {
  if (value.trim().length >= 6) {
    // 正则表达式验证是否是数组和字母的组合
    if (/^[a-zA-Z0-9]+$/.test(value)) {
      callback();
    } else {
      callback(new Error("密码只能是数组和字母组合"));
    }
  } else {
    callback(new Error("密码至少六位"));
  }
};
// 添加和修改表单数据的验证规则(触发时机不要用change，因为添加时会重置数据，会触发表单校验)
const rules = ref({
  username: [{ required: true, validator: userNameRules, trigger: "blur" }],
  name: [{ required: true, validator: nameRules, trigger: "blur" }],
  password: [{ required: true, validator: pwdRules, trigger: "blur" }],
});
// 全选复选框控制
const checkAll = ref(false);
// 全选复选框中间状态
const isIndeterminate = computed(() => {
  return hasRoles.value.length > 0 && hasRoles.value.length < allRoles.value.length;
});
// 全选复选框全选
// 所有角色
const allRoles = ref<RoleObj[]>([]);
// 已设置的角色
const hasRoles = ref<RoleObj[]>([]);
// 批量删除的用户Id
let selectUserId = ref<number[]>([]);
// 搜索输入框数据
const searchValue = ref("");

onMounted(() => {
  getUserList();
});
// 获取用户账号信息
const getUserList = async (curPage = 1) => {
  currentPage.value = curPage;
  let result: UserResData = await reqUserList(
    currentPage.value,
    pageSize.value,
    searchValue.value.trim()
  );
  if (result?.code === 200) {
    userList.value = result.data?.records;
    total.value = result.data?.total;
  } else {
    ElMessage.error("获取用户账号信息失败");
  }
};
// 当前页改变事件回调
const curPageChange = () => {
  getUserList(currentPage.value);
};
// 页面显示条数改变事件回调
const pageSizeChange = () => {
  getUserList();
};
// 添加用户按钮回调
const addUser = () => {
  // 显示抽屉
  addOrEditDrawerShow.value = true;
  // 清空缓存数据
  userFormData.value = {
    username: "",
    password: "",
    name: "",
  };
  // 清空表单验证信息
  nextTick(() => {
    formRef.value.clearValidate(["username", "name", "password"]);
  });
};
// 修改用户按钮回调
const updateUser = (row: UserObj) => {
  // 显示抽屉
  addOrEditDrawerShow.value = true;
  // 保存修改之前的用户名
  oldUserName.value = row.username;
  // 数据回显
  userFormData.value = JSON.parse(JSON.stringify(row));
  // 清空表单验证信息
  nextTick(() => {
    formRef.value.clearValidate(["username", "name", "password"]);
  });
};
// 添加和修改用户的保存按钮回调
const saveUserInfo = () => {
  // 验证表单内容是否通过规则校验
  formRef.value.validate(async (valid: boolean) => {
    if (valid) {
      // 通过校验
      if (userFormData.value.id) {
        // 存在id，修改用户信息
        let result = await reqEditUser(userFormData.value);
        if (result?.code === 200) {
          ElMessage.success("修改成功");
          // 关闭抽屉
          addOrEditDrawerShow.value = false;
          // 重新获取用户信息
          getUserList(currentPage.value);
          // 避免用户修改了自己的信息，导致信息展示错误，这里需要刷新浏览器
          // 判断当前登录用户的名字是否和要修改的用户名字相同（细节点）
          if (userFormData.value.id && userStore.username === oldUserName.value) {
            window.location.reload();
          }
        } else {
          ElMessage.error("修改失败");
          // 关闭抽屉
          addOrEditDrawerShow.value = false;
        }
      } else {
        // 不存在id，新增用户信息
        let result = await reqAddUser(userFormData.value);
        if (result?.code === 200) {
          ElMessage.success("添加成功");
          // 关闭抽屉
          addOrEditDrawerShow.value = false;
          // 重新获取用户信息
          getUserList();
        } else {
          ElMessage.error("添加失败");
          // 关闭抽屉
          addOrEditDrawerShow.value = false;
        }
      }
    }
  });
};
// 分配角色按钮回调
const assignRole = async (row: UserObj) => {
  // 打开抽屉
  assignRoleDrawerShow.value = true;
  // 数据回显
  userFormData.value = JSON.parse(JSON.stringify(row));
  // 获取所有角色和已分配角色
  let result: RoleResData = await reqAllOrHasRoles(row.id as number);
  if (result.code === 200) {
    allRoles.value = result.data?.allRolesList;
    hasRoles.value = result.data?.assignRoles;
  } else {
    ElMessage.error("获取角色失败");
  }
};
// 全选复选框change事件
const handleCheckAllChange = (status: boolean) => {
  // 若全选，则将全部角色赋值给已有角色；若不全选，则赋值空数组
  hasRoles.value = status ? allRoles.value : [];
};
// 角色复选框change事件
const handleRoleCheckChange = (value: string[]) => {
  // 已选角色数组的长度
  let length = value.length;
  checkAll.value = length === allRoles.value.length;
};
// 保存用户分配角色按钮回调
const saveRoleInfo = async () => {
  // 收集接口数据
  let roleFormData: AssignRoleObj = {
    userId: userFormData.value.id as number,
    roleIdList: hasRoles.value.map((item) => item.id as number),
  };
  // 发送请求
  let result: any = await reqAssignRole(roleFormData);
  if (result?.code === 200) {
    ElMessage.success("分配角色成功");
    assignRoleDrawerShow.value = false;
    getUserList(currentPage.value);
  } else {
    ElMessage.error("分配用户失败");
    assignRoleDrawerShow.value = false;
  }
};
// 删除用户按钮回调
const deleteUser = async (row: UserObj) => {
  let result: any = await reqDeleteUser(row.id as number);
  if (result.code === 200) {
    ElMessage.success("用户删除成功");
    userList.value.length > 1
      ? getUserList(currentPage.value)
      : getUserList(currentPage.value - 1);
  } else {
    ElMessage.error("用户删除失败");
  }
};
// 批量删除用户按钮回调
const deleteMutiUser = async () => {
  // 获取选中的用户信息
  let selectUser: UserObj[] = tableRef.value.getSelectionRows();
  // 取出用户的id，形成数组
  selectUserId.value = selectUser.map((item) => item.id as number);
  let result = await reqBatchDeleteUser(selectUserId.value);
  if (result.code === 200) {
    ElMessage.success("用户批量删除成功");
    userList.value.length > selectUserId.value.length
      ? getUserList(currentPage.value)
      : getUserList(currentPage.value - 1);
  } else {
    ElMessage.error("用户批量删除失败");
  }
};
// 搜索用户
const searchUser = async () => {
  // 获取用户数据
  getUserList();
};
// 重置用户数据
const resetData = () => {
  searchValue.value = "";
  getUserList();
};
</script>

<style scoped lang="scss">
.form {
  display: flex;
  justify-content: space-between;
  .el-form-item {
    margin-bottom: 0px;
  }
}
</style>
